#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "list.h"
#include "msg_queue_peer.h"
#include "shmem.h"
#include "cJSON.h"
#define PORT 6789
#define NODE_JOSON "./node.json"
#define QUEUE_TOPIC "stm32topic"

/* 共享内存相关 */
#define MAX_NODE 10 //最大支持设备，实际可用是9
#define STD_NODE_LEN sizeof(struct std_node)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN) //共享内存的大小
#define SHM_TOPIC "shm_test"

//共享内存中存放的节点类型
union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

//共享内存存储的节点
struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};

static struct shm_param para;
static int *total;                //共享内存中存储的节点数
static struct std_node *node_arr; //指向共享内存中节点缓存数组头

//消息队列的消息结构体
struct msgbuf
{
    long mtype;      // 消息类型，以dev_type区分，0表示stm32,1表示modbus
    char mdata[256]; // 里面是包含key，val的JSON格式的字符串
};

//点表结构体
struct data
{
    int key;
    int type;
    char name[16];
    struct list_head list;
};

struct list_head head;
int acceptfd;
void *myhandler(void *arg);
void *myhandler2(void *arg);                           //线程处理函数
int init_shm(void);                                    //初始化共享内存，存放点表
void xuliehua(char buf[256], int acceptfd);            //反序列化32接收的内容，并且写入共享内存
void unxuliehua(struct msgbuf recv_buf, int acceptfd); //反序列化消息队列中控制指令,并发送至32

int main(int argc, char const *argv[])
{
    init_shm();
    //创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }

    //填充IPV4结构体
    struct sockaddr_in Serveraddr, Clientaddr;
    Serveraddr.sin_family = AF_INET;
    Serveraddr.sin_port = htons(PORT);
    //Serveraddr.sin_port = htons((short)atoi((char *)PORT));
    Serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");

    socklen_t len = sizeof(Clientaddr);

    //绑定套接字
    if (bind(sockfd, (struct sockaddr *)&Serveraddr, len) < 0)
    {
        perror("bind err.");
        return -1;
    }

    //监听
    if (listen(sockfd, 10))
    {
        perror("listen err.");
        return -1;
    }

    //char *p = NULL; //接受数据指针
    //阻塞连接客户端
    pthread_t tid2;
    pthread_create(&tid2, NULL, myhandler2, NULL);
    pthread_detach(tid2); //子线程终止时，自动回收资源
    while (1)
    {
        acceptfd = accept(sockfd, (struct sockaddr *)&Clientaddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err.");
            return -1;
        }
        printf("acceptfd:%d\n", acceptfd);
        printf("Client Port:%d,IP:%s\n", Clientaddr.sin_port, inet_ntoa(Clientaddr.sin_addr));

        pthread_t tid;
        pthread_create(&tid, NULL, myhandler, (void *)&acceptfd);
        pthread_detach(tid); //子线程终止时，自动回收资源

        //循环读消息队列，然后发送
        //进行链表数据处理
    }

    close(sockfd);
    return 0;
}

void *myhandler(void *arg)
{
    int acceptfd = *((int *)arg);

    char recv_buf[256] = {0};
    while (1)
    {
        size_t byte = recv(acceptfd, recv_buf, sizeof(recv_buf), 0);
        if (byte < 0)
        {
            perror("recv err.");
            printf("line:%d\n", __LINE__);
            return NULL;
        }
        else if (0 == byte)
        {
            printf("Client quit,pid:%d", getpid());
            break;
        }
        else
        {
            printf("recv_buf from 32:%s\n", recv_buf); //打印32接收的内容
            xuliehua(recv_buf, acceptfd);              //反序列化32接收的内容，并且写入共享内存
            memset(recv_buf,0,sizeof(recv_buf));
        }
    }

    close(acceptfd);
    pthread_exit(NULL);
}

void *myhandler2(void *arg)
{
    //int acceptfd = *((int *)arg);
    struct msgbuf recv_buf;
    while (1)
    {
        if (acceptfd >= 4)
        {
            if (msg_queue_recv(QUEUE_TOPIC, &recv_buf, sizeof(recv_buf), 1, 0) > 0) //
            {
                //反序列化消息队列控制指令
                unxuliehua(recv_buf, acceptfd);
            }
            else
            {
                perror("recv error:");
                continue;
            }
        }
    }
    pthread_exit(NULL);
}

/* 初始化共享内存，打开点表存放进内核链表 */
int init_shm(void)
{
    int ret = -1;
    ret = shm_init(&para, SHM_TOPIC, MAX_NODE_SIZE);
    if (ret < 0)
    {
        perror("shm_init err.");
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    total = (int *)node_p; //设备数量
    *total = 8;
    node_arr = (struct std_node *)(node_p + sizeof(int)); //存放数据的起始地址

    FILE *fp = fopen(NODE_JOSON, "r");
    if (NULL == fp)
    {
        perror("fopen err");
        return -1;
    }
    //读文件
    char buf[2048] = {0};
    size_t len = fread(buf, 1, 2048, fp);
    if (len < 0)
    {
        perror("fread err");
        return -1;
    }

    //将字符串转成JSON结构
    cJSON *root = cJSON_Parse(buf);
    if (root == NULL)
    {
        printf("prase err\n");
        return -1;
    }

    //找到32部分
    cJSON *item = cJSON_GetObjectItem(root, "stm32");
    cJSON *array = cJSON_GetObjectItem(item, "data");
    int num = cJSON_GetArraySize(array);
    cJSON *temp = NULL;
    INIT_LIST_HEAD(&head);

    //循环头插进链表
    for (int i = 0; i < num; i++)
    {
        struct data *d = (struct data *)malloc(sizeof(struct data));
        if (d == NULL)
        {
            perror("malloc err");
        }
        item = cJSON_GetArrayItem(array, i);
        temp = cJSON_GetObjectItem(item, "key");
        d->key = temp->valueint;
        temp = cJSON_GetObjectItem(item, "type");
        d->type = temp->valueint;
        temp = cJSON_GetObjectItem(item, "name");
        strcpy(d->name, temp->valuestring);
        list_add(&d->list, &head);
    }
    struct list_head *pos;
    struct data *tmp;
    // list_for_each(pos, &head)
    // {
    //     tmp = list_entry(pos, struct data, list);
    //     printf("%s\n", tmp->name);
    // }
    cJSON_Delete(root);
    fclose(fp);
}

//反序列化32接收的内容，并且写入共享内存
void xuliehua(char buf[258], int acceptfd)
{
    cJSON *root = cJSON_Parse(buf);
    struct list_head *pos;
    struct data *temp;
    list_for_each(pos, &head)
    {
        temp = list_entry(pos, struct data, list);
        if (temp->type == 1)
        {
            if (cJSON_HasObjectItem(root, temp->name))
            {
                cJSON *val = cJSON_GetObjectItem(root, temp->name);
                for (int i = 0; i < *total; i++)
                {
                    if (node_arr[i].key == temp->key)
                    {
                        node_arr[i].old_val.b_val = node_arr[i].new_val.b_val;
                        node_arr[i].new_val.b_val = val->valueint;
                    }
                }
            }
        }
        else if (temp->type == 2)
        {
            if (cJSON_HasObjectItem(root, temp->name))
            {
                cJSON *val = cJSON_GetObjectItem(root, temp->name);
                for (int i = 0; i < *total; i++)
                {
                    if (node_arr[i].key == temp->key)
                    {
                        node_arr[i].old_val = node_arr[i].new_val;
                        node_arr[i].new_val.i_val = atoi(val->valuestring);
                        // printf("%d\n", node_arr[i].new_val.i_val);
                    }
                }
            }
        }
        else if (temp->type == 3)
        {
            if (cJSON_HasObjectItem(root, temp->name))
            {
                cJSON *val = cJSON_GetObjectItem(root, temp->name);
                for (int i = 0; i < *total; i++)
                {
                    if (node_arr[i].key == temp->key)
                    {
                        node_arr[i].old_val.f_val = node_arr[i].new_val.f_val;
                        node_arr[i].new_val.f_val = atof(val->valuestring);
                        //printf("%f\n", node_arr[i].new_val.f_val);
                    }
                }
            }
        }
    }
    cJSON_Delete(root);
}

//反序列化消息队列中的控制指令,并发送至32
void unxuliehua(struct msgbuf recv_buf, int acceptfd)
{
    //反序列化
    cJSON *root = cJSON_Parse(recv_buf.mdata);
    cJSON *data = cJSON_GetObjectItem(root, "data");
    cJSON *item_key = cJSON_GetObjectItem(data, "key");
    cJSON *item_val = cJSON_GetObjectItem(data, "val");
    cJSON *root2 = cJSON_CreateObject();
    struct list_head *pos;
    struct data *temp;
    list_for_each(pos, &head)
    {
        temp = list_entry(pos, struct data, list);
        if (temp->type == 1 && temp->key == item_key->valueint)
        {
            cJSON *val = cJSON_CreateNumber(atoi(item_val->valuestring));
            cJSON_AddItemToObject(root2, temp->name, val);
        }
        else if (temp->type == 2 && temp->key == item_key->valueint)
        {
            cJSON *val = cJSON_CreateNumber(atoi(item_val->valuestring));
            cJSON_AddItemToObject(root2, temp->name, val);
        }
        else if (temp->type == 3 && temp->key == item_key->valueint)
        {
            cJSON *val = cJSON_CreateNumber(atof(item_val->valuestring));
            cJSON_AddItemToObject(root2, temp->name, val);
        }
    }
    //char *p = cJSON_Print(root2);
    char *p = cJSON_PrintUnformatted(root2);
    printf("send to wifi buf:%s\n", p);
    send(acceptfd, p, strlen(p), 0);
    free(p);

    cJSON_Delete(root);
    cJSON_Delete(root2);
}
